home *** CD-ROM | disk | FTP | other *** search
- /* @(#) $Id: krnlif.c,v 1.4 1997/09/14 14:37:46 root Exp root $ */
-
- #ifdef linux
-
- /*****************************************************************************/
-
- /*
- * krnlif.c -- directly attach a linux kernel interface.
- *
- * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * What does it?
- * This module allows WAMPES to directly attach to a Linux Kernel
- * AX.25 driver.
- * Why?
- * Many drivers for Packet Radio Hardware are nowadays only provided
- * as Linux Kernel network drivers. Character KISS drivers are dying out,
- * simply because the network driver interface is much cleaner, simpler
- * and faster than the complicated line discipline stuff needed by a
- * character driver.
- * To use such an interface in Wampes, one could use the net2kiss program
- * from the ax25 utilities, that would convert such interface packets
- * to a KISS data stream on a pseudo tty. Wampes could then attach the
- * respective slave tty. This is complicated to set up, and involves
- * some overhead.
- * This module now allows Wampes to directly attach such Linux Kernel
- * interfaces.
- * Example:
- * To set up Wampes with a Baycom SER12 modem, the following steps are
- * necessary.
- * In a shell:
- * insmod hdlcdrv.o
- * insmod baycom.o modem=1 iobase=0x3f8 irq=4 options=1
- * From within Wampes (or cnet):
- * attach kernel bc0
- * Note:
- * the attach command automatically brings the interface into the
- * running and promiscious state. The MTU is taken from the Linux
- * interface settings, but may be changed. attach remembers the interface
- * state and restores it at detach, i.e. if you quit wampes.
- * AX.25 kernel interfaces may be loaded into memory even if Kernel
- * AX.25 is disabled.
- *
- * This module is Linux specific. SOCK_PACKET is the Linux way to get
- * packets at the raw interface level.
- *
- * Modified extensively for TNOS (brian@lantz.com)
- * Added capability to also link IP into the kernel with added parameter
- *
- */
-
- /*lint -save -e508 -e27 -e532 -e14 -e18 -e15 -e516 -e114 */
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/ioctl.h>
- #include <errno.h>
- #include <net/if.h>
- #ifdef HAVE_NETINET_IF_ETHER_H
- #include <netinet/if_ether.h>
- #include <net/if_arp.h>
- #include <netinet/in.h>
- #else
- #include <linux/if_ether.h>
- #include <linux/if_arp.h>
- #include <linux/in.h>
- #endif
-
- #undef LOCK
- #define _SOCKET_H
- #define _SOCKADDR_H
- #include "global.h"
- #include "iface.h"
- /*lint -restore */
- #include "commands.h"
- #include "devparam.h"
- #include "trace.h"
- #include "hardware.h"
- #include "enet.h"
-
- #define KRNLIF_MAX 16
-
- /* kernel interface control block */
- struct krnlif {
- struct iface *iface;
-
- int fd; /* File descriptor */
-
- struct mbuf *sndq; /* Transmit queue */
-
- short oldflags; /* used to restore the interrupt flags */
- int proto; /* protocol to listen for */
- int promisc; /* set interface to promiscious mode */
- int class; /* device class (for dump) */
-
- long rxpkts; /* receive packets */
- long txpkts; /* transmit packets */
- long rxchar; /* Received characters */
- long txchar; /* Transmitted characters */
- };
-
- static struct krnlif KrnlIf[KRNLIF_MAX];
-
-
- static void krnlif_rx(int dev, void *v1, void *v2);
-
-
- /*---------------------------------------------------------------------------*/
-
- static int krnlif_up(struct krnlif *ki)
- {
- struct ifreq ifr;
- struct sockaddr sa;
- char *cp;
-
- if (ki->fd >= 0) /* Already UP */
- return 0;
- if ((ki->fd = socket(PF_INET, SOCK_PACKET, ki->proto)) < 0)
- goto Fail;
- strcpy(ifr.ifr_name, ki->iface->name);
- if (ioctl(ki->fd, SIOCGIFFLAGS, &ifr) < 0)
- goto Fail;
- ki->oldflags = ifr.ifr_flags;
- ifr.ifr_flags |= IFF_UP;
- if (ki->promisc)
- ifr.ifr_flags |= IFF_PROMISC;
- if (ioctl(ki->fd, SIOCSIFFLAGS, &ifr) < 0)
- goto Fail;
- strcpy(sa.sa_data, ki->iface->name);
- sa.sa_family = AF_INET;
- if (bind(ki->fd, &sa, sizeof(struct sockaddr)) < 0)
- goto Fail;
-
- register_io (ki->fd, &ki->fd);
-
- cp = if_name (ki->iface, " rx");
- ki->iface->rxproc = newproc (cp, 768, krnlif_rx, ki->iface->dev, ki->iface, NULL, 0);
- ki->iface->rxproc->ptype = PTYPE_IO;
-
- return 0;
-
- Fail:
- if (ki->fd >= 0) {
- close(ki->fd);
- ki->fd = -1;
- }
- return -1;
- }
-
- /*---------------------------------------------------------------------------*/
-
- static int krnlif_down(struct krnlif *ki)
- {
- struct ifreq ifr;
-
- if (ki->fd < 0) /* Already DOWN */
- return 0;
-
- unregister_io (ki->fd);
- free_q(&ki->sndq);
- strcpy(ifr.ifr_name, ki->iface->name);
- ifr.ifr_flags = ki->oldflags;
- (void) ioctl(ki->fd, SIOCSIFFLAGS, &ifr);
- killproc (ki->iface->rxproc);
- ki->iface->rxproc = NULLPROC;
- close(ki->fd);
- ki->fd = -1;
- return 0;
- }
-
- /*---------------------------------------------------------------------------*/
-
- /* Asynchronous line I/O control */
-
- static int32 krnlif_ioctl(struct iface *ifp, int cmd, int set OPTIONAL, int32 val OPTIONAL)
- {
- struct krnlif *ki;
-
- if (!ifp || ifp->dev < 0 || ifp->dev >= KRNLIF_MAX)
- return -1;
- ki = KrnlIf + ifp->dev;
-
- switch(cmd){
- case PARAM_DOWN:
- return krnlif_down(ki) ? 0 : 1;
- case PARAM_UP:
- return krnlif_up(ki) ? 0 : 1;
- default:
- return -1;
- }
- }
-
- /*---------------------------------------------------------------------------*/
-
- static int krnlif_raw(struct iface *iface, struct mbuf *bp)
- {
- struct krnlif *ki;
- struct sockaddr to;
- uint8 buf[4096]; /* should be enough */
- uint8 *bufp = buf;
- struct mbuf *bp2;
- int cnt = 0;
- int i;
-
- ki = KrnlIf + iface->dev;
- dump (iface, IF_TRACE_OUT, (unsigned) ki->class, bp);
-
- iface->rawsndcnt++;
- iface->lastsent = secclock();
- if (iface->trace & IF_TRACE_RAW)
- raw_dump(iface, -1, bp);
- if (iface->dev < 0 || iface->dev >= KRNLIF_MAX){
- free_p (bp);
- return -1;
- }
-
- if (ki->iface == NULL || ki->fd < 0)
- free_p (bp);
- else {
- for (bp2 = bp; bp2; bp2 = bp2->next) {
- cnt += bp2->cnt;
- if (cnt > (int) sizeof(buf)) {
- (void) free_mbuf (bp);
- return -1;
- }
- memcpy (bufp, bp2->data, bp2->cnt);
- bufp += bp2->cnt;
- }
- strncpy(to.sa_data, ki->iface->name, sizeof(to.sa_data));
-
- i = sendto(ki->fd, buf, (unsigned) cnt, 0, &to, sizeof(to));
-
- if (i >= 0) {
- ki->txpkts++;
- ki->txchar += i;
- (void) free_mbuf(bp);
- return 0;
- }
- if (errno == EMSGSIZE) {
- (void) free_mbuf(bp);
- return -1;
- }
- if (errno == EWOULDBLOCK)
- return 0;
- (void) krnlif_down(ki);
- }
- return 0;
- }
-
- /*---------------------------------------------------------------------------*/
-
- static void krnlif_rx (int dev OPTIONAL, void *v1, void *v2 OPTIONAL)
- {
- struct iface *iface = (struct iface *) v1;
- struct krnlif *ki;
- struct sockaddr from;
- int from_len = sizeof(from);
- int i;
- struct mbuf *bp;
-
- server_disconnect_io ();
- if (!iface || iface->dev < 0 || iface->dev >= KRNLIF_MAX)
- return;
- ki = KrnlIf + iface->dev;
-
- for ( ; ; ) {
- kwait (&ki->fd);
- if ((bp = alloc_mbuf(ki->iface->mtu+16)) == 0)
- return;
- i = recvfrom(ki->fd, bp->data, bp->size, 0, &from, &from_len);
- if (i <= 0) {
- if (i < 0 || errno != EWOULDBLOCK)
- (void) krnlif_down(ki);
- (void) free_mbuf(bp);
- ki->iface->rxproc = NULLPROC;
- return;
- }
- bp->cnt = (int16) i;
- ki->rxpkts++;
- ki->rxchar += i;
- if (ki->iface->trace & IF_TRACE_RAW)
- raw_dump(ki->iface, IF_TRACE_IN, bp);
-
- (void) net_route(ki->iface, ki->class, bp);
- }
- }
-
- /*---------------------------------------------------------------------------*/
-
- static void krnlif_status(struct iface *iface)
- {
- struct krnlif *ki;
-
- if (!iface || iface->dev < 0 || iface->dev >= KRNLIF_MAX)
- return;
- ki = KrnlIf + iface->dev;
- if (ki->iface != iface)
- return;
-
- tprintf(" Received: Packets %8ld Chars %8ld\n"
- " Transmitted: Packets %8ld Chars %8ld\n",
- ki->rxpkts, ki->rxchar, ki->txpkts, ki->txchar);
- }
-
- /*---------------------------------------------------------------------------*/
-
- static int krnlif_detach(struct iface *ifp)
- {
- struct krnlif *ki;
-
- if (ifp == NULL)
- return -1;
- if (ifp->dev < 0 || ifp->dev >= KRNLIF_MAX)
- return -1;
- ki = KrnlIf + ifp->dev;
- if(ki->iface == NULL)
- return -1; /* Not allocated */
- (void) krnlif_down(ki);
- ki->iface = NULL;
- return 0;
- }
-
- /*---------------------------------------------------------------------------*/
-
- static struct hwencap {
- unsigned short family;
- char const *encap;
- int class;
- } hwencap[] = {
- #ifdef NETROM
- { ARPHRD_NETROM, "NETROM", 16 /* CL_NETROM */ },
- #endif
- { ARPHRD_ETHER, "Ethernet", 1 /* CL_ETHERNET */ },
- #ifdef KISS
- { ARPHRD_AX25, "AX25", 9 /* CL_AX25 */ },
- #endif
- #ifdef ARPHRD_LOOPBACK
- { ARPHRD_LOOPBACK, "None", 0 /* CL_NONE */ },
- #endif
- { 0, 0, 0 }
- };
-
- int krnlif_attach(int argc, char *argv[], void *p OPTIONAL)
- {
- struct iface *ifp;
- int dev;
- struct krnlif *ki;
- struct ifreq ifr;
- struct sockaddr hw;
- struct sockaddr_in in;
- int fd;
- struct hwencap *hwe = hwencap;
-
- if (if_lookup(argv[1]) != NULL) {
- tprintf("Interface %s already exists\n",argv[4]);
- return -1;
- }
- /*
- * get parameters of the interface
- */
- if ((fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL))) < 0) {
- tprintf ("socket error: %s\n", strerror (errno));
- return -1;
- }
- strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name));
- ifr.ifr_addr.sa_family = AF_INET;
- if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
- tprintf ("ioctl error (SIOCGIFADDR): %s\n", strerror (errno));
- tprintf("cannot get inet addr for interface %s\n", argv[1]);
- return -1;
- }
- if (ifr.ifr_addr.sa_family != AF_INET) {
- tprintf("Interface %s: not AF_INET, %d\n", argv[1],
- ifr.ifr_addr.sa_family);
- return -1;
- }
- memcpy(&in, &ifr.ifr_addr, sizeof(in));
- ifr.ifr_addr.sa_family = AF_UNSPEC;
- if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
- tprintf ("ioctl error (SIOCGIFADDR): %s\n", strerror (errno));
- tprintf("cannot get hw addr for interface %s\n", argv[1]);
- return -1;
- }
- hw = ifr.ifr_hwaddr;
- for (; (hwe->family != hw.sa_family) && (hwe->encap != NULL); hwe++)
- ;
- if (hwe->family != hw.sa_family) {
- tprintf("Interface %s: invalid ARP type %d\n", argv[1],
- hw.sa_family);
- return -1;
- }
- if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
- tprintf ("ioctl error (SIOCGIFMTU): %s\n", strerror (errno));
- tprintf("cannot get mtu for interface %s\n", argv[1]);
- return -1;
- }
-
- /* Find unused krnlif control block */
- for (dev=0; (dev < KRNLIF_MAX) && (KrnlIf[dev].iface); dev++)
- ;
- if (dev >= KRNLIF_MAX){
- tprintf("Too many kernel interfaces\n");
- return -1;
- }
- ki = KrnlIf+dev;
- /* Create interface structure and fill in details */
- ifp = (struct iface *)callocw(1,sizeof(struct iface));
- ifp->addr = Ip_addr /*in.sin_addr.s_addr*/;
- ifp->name = strdup(argv[1]);
- ifp->mtu = (int16) ifr.ifr_mtu;
- ifp->dev = dev;
- ifp->stop = krnlif_detach;
- /* set encapsulation */
- (void) setencap(ifp, hwe->encap);
- ki->class = hwe->class;
- ifp->ioctl = krnlif_ioctl;
- ifp->raw = krnlif_raw;
- ifp->show = krnlif_status;
- ifp->xdev = dev;
-
- /* set hwaddr */
- switch (hw.sa_family) {
- case ARPHRD_AX25: if (ifp->hwaddr == NULL)
- ifp->hwaddr = (char *) mallocw(AXALEN);
- memcpy(ifp->hwaddr, Mycall, AXALEN);
- ki->proto = htons(ETH_P_AX25);
- ki->promisc = !((argc >= 3) && !strcmp(argv[2], "nopromisc"));;
- break;
- case ARPHRD_LOOPBACK:
- case ARPHRD_ETHER:
- default:
- ifp->hwaddr = mallocw (ETHERLEN);
- memcpy (ifp->hwaddr, hw.sa_data, ETHERLEN);
- ki->proto = htons(ETH_P_ALL);
- ki->promisc = 1;
- break;
- }
-
- close (fd);
- ki->fd = -1;
- ki->iface = ifp;
-
- /* Link in the interface */
- ifp->next = Ifaces;
- Ifaces = ifp;
-
- return krnlif_up(ki);
- }
-
- /*---------------------------------------------------------------------------*/
-
-
- #endif
-